﻿using Aliyun.OSS;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Common.Aliyun
{
    /// <summary>
    /// OSS对象下载
    /// </summary>
    public class OSSObjectDownload
    {
        private readonly static ConcurrentDictionary<string, HttpClient> httpPool = new ConcurrentDictionary<string, HttpClient>();
        private readonly IConfiguration configuration;
        private readonly ConfigHelper configHelper;
        /// <summary>
        /// OSS对象下载
        /// </summary>
        /// <param name="_configuration"></param>
        public OSSObjectDownload(IConfiguration _configuration)
        {
            this.configuration = _configuration;
            this.configHelper = new ConfigHelper(this.configuration);
        }
        /// <summary>
        /// 下载文件，使用内网地址下载
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public MemoryStream Download(string url)
        {
            return Download(url, true);
        }
        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="url"></param>
        /// <param name="useInternal">是否使用内网地址下载</param>
        /// <returns></returns>
        public MemoryStream Download(string url, bool useInternal)
        {
            var objectUri = new Uri(url);
            string ossDomainConfig = this.configuration["OSSDomainMapping"];
            List<OSSDomainConfig> domains = JsonConvert.DeserializeObject<List<OSSDomainConfig>>(ossDomainConfig);
            var matchDomain = domains.Find(x => objectUri.Host.Contains(x.Domain));
            if (matchDomain == null)
            {
                return DownloadNormalFile(url).ConfigureAwait(false).GetAwaiter().GetResult();
            }
            string objectName = objectUri.AbsolutePath.TrimStart('/');
            string bucket = string.IsNullOrEmpty(matchDomain.Bucket) ? objectUri.Host.Substring(0, objectUri.Host.IndexOf('.')) : matchDomain.Bucket;
            return Download(objectName, bucket, useInternal);
        }
        ///// <summary>
        ///// 下载图片，并压缩到maxLength以下
        ///// <para>CAUTION: use this method in linux, please ensure that platform has [libgdiplus] program installed</para>
        ///// <para>注意：在linux环境下使用此方法必须保证环境有安装【libgdiplus】程序</para>
        ///// </summary>
        ///// <param name="url"></param>
        ///// <param name="maxLength"></param>
        ///// <returns></returns>
        //public MemoryStream Download(string url, int maxLength)
        //{
        //    var stream = Download(url);
        //    if (stream.Length <= maxLength)
        //    {
        //        return stream;
        //    }
        //    return CompressImage(stream, maxLength);
        //}
        ///// <summary>
        ///// 压缩图片
        ///// </summary>
        ///// <param name="stream"></param>
        ///// <param name="maxLength">单位KB</param>
        ///// <returns></returns>
        //private static MemoryStream CompressImage(MemoryStream stream, int maxLength)
        //{
        //    try
        //    {
        //        maxLength = maxLength < 10 ? 10 : maxLength;
        //        int size = maxLength * 1024;
        //        if (stream == null || stream.Length <= size)
        //        {
        //            return stream;
        //        }
        //        var rate = stream.Length / size;
        //        var step = 0.1m;
        //        if (rate > 1 && rate <= 5)
        //        {
        //            step = 0.2m;
        //        }
        //        else if (rate > 5 && rate <= 10)
        //        {
        //            step = 0.3m;
        //        }
        //        else if (rate > 10 && rate <= 20)
        //        {
        //            step = 0.4m;
        //        }
        //        else if (rate > 20)
        //        {
        //            step = 0.5m;
        //        }
        //        var image = Image.FromStream(stream);
        //        //每次缩小10%
        //        int reduceWidth = (int)(image.Width * step);
        //        int reduceHeight = (int)(image.Height * step);
        //        var width = image.Width - reduceWidth;
        //        var height = image.Height - reduceHeight;
        //        Bitmap thumb = new Bitmap(width, height);
        //        Graphics g = Graphics.FromImage(thumb);
        //        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
        //        g.SmoothingMode = SmoothingMode.HighQuality;
        //        g.PixelOffsetMode = PixelOffsetMode.HighQuality;
        //        g.CompositingQuality = CompositingQuality.HighQuality;
        //        g.DrawImage(image, 0, 0, width, height);
        //        MemoryStream thumbStream = new MemoryStream();
        //        thumb.Save(thumbStream, image.RawFormat);
        //        return CompressImage(thumbStream, maxLength);//, times);
        //    }
        //    catch (Exception ex)
        //    {
        //        Console.WriteLine($"图片压缩失败，{ex.Message}");
        //        return stream;
        //    }
        //}
        /// <summary>
        /// 下载文件，使用内网地址下载
        /// </summary>
        /// <param name="objectName">OSS对象名称</param>
        /// <param name="bucket">OSS文件桶名称</param>
        /// <returns></returns>
        public MemoryStream Download(string objectName, string bucket)
        {
            return Download(objectName, bucket, true);
        }
        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="objectName"></param>
        /// <param name="bucket"></param>
        /// <param name="useInternal">是否使用内网下载</param>
        /// <returns></returns>
        public MemoryStream Download(string objectName, string bucket, bool useInternal)
        {
            var credential = STSCredential.GetSTSCredentail(bucket, this.configuration);
            if (credential == null)
            {
                return null;
            }
            var endpoint = this.configHelper.GetBucketEndPoint(bucket);
            string url = useInternal ? endpoint.InternalEndpoint : endpoint.EndPoint;
            // 创建OSSClient实例。
            var client = new OssClient(url, credential.AccessKeyId, credential.AccessKeySecret, credential.SecurityToken);
            var obj = client.GetObject(bucket, objectName);
            MemoryStream ms = new MemoryStream();
            using (var requestStream = obj.Content)
            {
                byte[] buf = new byte[1024];

                var len = 0;
                // 通过输入流将文件的内容读取到文件或者内存中。
                while ((len = requestStream.Read(buf, 0, 1024)) != 0)
                {
                    ms.Write(buf, 0, len);
                }
            }
            return ms;
        }
        private async Task<MemoryStream> DownloadNormalFile(string url)
        {
            var uri = new Uri(url);
            string domain = string.Concat(uri.Scheme, "://", uri.Host);
            var client = httpPool.GetOrAdd(domain, d =>
            {
                var http = new HttpClient();
                http.BaseAddress = new Uri(d);
                return http;
            });
            var response = await client.GetAsync(url);
            var bytes = await response.Content.ReadAsByteArrayAsync();
            return new MemoryStream(bytes);
        }
    }
}
